{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# TorchSig: Getting Started\n",
    "This notebook gives an overview of the terms and capabilities of TorchSig.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Signals\n",
    "A signal has many definitions in the digital signal processing, radio frequency, and machine learning world. Below we define precisely what we define as certain signals.\n",
    "\n",
    "* **SignalMetadata**: Object that contains all the metadata for a Signal. There are 7 **core** metadata fields:\n",
    "    * center_freq: Normalized center frequency of signal.\n",
    "    * bandwidth: Normalized bandwidth of signal.\n",
    "    * start_in_samples: Start time of signal in terms of IQ data array idx.\n",
    "    * duration_in_samples: Duration of signal in terms of IQ data array idx.\n",
    "    * snr_db: Signal-to-Noise ratio in dB.\n",
    "    * class_name: Signal class name/modulation type.\n",
    "    * class_index: Class index of signal in dataset, which contains a list of all modulations being used.\n",
    "    \n",
    "    Then there are **derived** metadata fields, which are calculate from the 7 core fields. Derived fields for example include lower_freq, upper_freq, start, stop, ect.\n",
    "* **Signal**: Object that represents a single signal burst. Contains IQ data and SignalMetadata. The **SignalBuilders** are responsible for creating a Signal object.\n",
    "* **DatasetSignal**: Contains the base noise floor with Signal(s) placed inside it. Also called a **sample**. This represents collecting signals over a set bandwidth.\n",
    "* **DatasetDict**: Same as DatasetSignal, but metadata is a list of dictionaries (that contain SignalMetadata). This makes performing target transforms much easier. Can also be called a **sample**.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Transforms\n",
    "\n",
    "### Functionals\n",
    "All core compute processes and logic parameters for transforms\n",
    "* functions perform fundamental operations, but do not define parameters or random distributions/sampling of how the operations are applied or randomized\n",
    "* Similiar to [Torchvision's transforms framework](https://pytorch.org/vision/0.9/transforms.html#functional-transforms)\n",
    "\n",
    "### Signal Transforms\n",
    "Applied to Signal objects, which are created from the SignalBuilders. In other words, transforms that are applied to isolated bursts before being placed on noise floor. These can be understood as transmitter effects on the Signal(s).\n",
    "\n",
    "Note that impairments are carefully applied within the SignalBuilder in a strict order to represent actual signal processing effects.\n",
    "\n",
    "### Dataset Transforms\n",
    "Applied to DatasetSignal objects, after all the IQ data of all Signal object(s) are placed onto the noise floor. These transforms are applied to the whole IQ data, including the bursts and noise floor. In particular, these transforms correspond to wideband effects, such as channel or receiver effects.\n",
    "\n",
    "### Dataset Impairments\n",
    "Impairments are a collections of SignalTransforms and DatasetTransforms that emulate different environments.\n",
    "* Level 1: Perfect environment, like inside a computer simulation. Has no transforms.\n",
    "* Level 2: Cabled environment. Contains some transforms that slightly impair the signals.\n",
    "* Level 3: Wireless environment. Contains many transforms that impair the signals greatly.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Datasets\n",
    "\n",
    "### Two Types: IQ vs. Spectrogram Image\n",
    "\n",
    "#### Synthetic IQ Datasets: Narrowband and Wideband\n",
    "* Narrowband\n",
    "* Wideband\n",
    "\n",
    "#### Synthetic Spectrogram Dataset: Image Datasets\n",
    "* Image datasets, cropping images to create a new dataset.\n",
    "* CFGSignalProtocolDataset\n",
    "\n",
    "### Dataset Objects\n",
    "These are the types of object you can instantiate in order to generate, create, or read a dataset.\n",
    "* DatasetMetadata:\n",
    "    * NarrowbandMetadata\n",
    "    * WidebandMetadtata\n",
    "* NewDataset: Dataset that can infinitely (or finite) generate signals in memory, but you cannot access previously generated samples.\n",
    "    * NewNarrowband, NewWideband\n",
    "* DatasetCreator: Takes in a NewDataset, and writes the dataset to disk.\n",
    "    * When a dataset is written or read from disk, it can either be **raw** or **processed**.\n",
    "    * **raw**: Raw IQ and signal metadata were written to disk. In other words, no transforms or target transforms were applied to the data. This means when the dataset is read back in, users can define their own transforms or target transforms to apply then. Note that impairment level cannot be changed once written to disk.\n",
    "    * **processed**: IQ data and/or metadata has transforms/target transforms applied. Thsi means that when the dataset is read back into memory, users cannot apply more transforms or target transforms.\n",
    "* StaticDataset: Reads in a dataset from disk. This assumes you have created a dataset using a DatasetCreator, and want to read it back in.\n",
    "    * StaticNarrowband, StaticWideband\n",
    "\n",
    "\n",
    "| I want... | Use |\n",
    "| --------- | ----- |\n",
    "| an infinite dataset | NewDataset |\n",
    "| to write a dataset to disk | NewDataset, DatasetCreator |\n",
    "| to load a dataset from disk | StaticDataset |\n",
    "| to write a dataset to disk, so someone else can use it with their own transforms/target transforms | NewDataset (no transforms or target transforms), DatasetCreator |\n",
    "| a finite dataset, where I can call previously generated samples | NewDataset, DatasetCreator, StaticDataset |\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Workflow\n",
    "\n",
    "### NewDataset\n",
    "The below diagram shows how a sample is generated from start to finish in a NewDataset's `__getitem__` method.\n",
    "\n",
    "![NEWDATASET](diagrams/new_dataset_workflow.png)\n",
    "\n",
    "### StaticDataset\n",
    "The below diagram shows how a sample is read in and optionally transformed in a StaticDataset's `__getitem__` method.\n",
    "\n",
    "![STATICDATSET](diagrams/static_dataset_workflow.png)\n",
    "\n",
    "---"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Julia 1.11.2",
   "language": "julia",
   "name": "julia-1.11"
  },
  "language_info": {
   "file_extension": ".jl",
   "mimetype": "application/julia",
   "name": "julia",
   "version": "1.11.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
